package com.bci.pwtz.servlet;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SecurityFilter implements Filter
{
    
    private String[]   strArray;
    
    private String[]   scriptArray;
    
    private String[] excludeUrls;
    
    // private String[] specialFileArray;
    
    private static Log logger = LogFactory.getLog("user.service");
    
    public SecurityFilter() {
        
    }
    
    public void destroy()
    {
        
    }
    private boolean isExclude(String url,String[] excludeUrls)
    {
        for(String s:excludeUrls)
        {
            if(url.indexOf(s) != -1)
                return true;
        }
        return false;
    }
    public void init(FilterConfig arg0) throws ServletException
    {
        String filterKey = "1 =1!1= 1!1 = 1!%20and%20!%20or%20!%20having%20!onreadystatechange!xss!script! eval !style!expression!iframe! img !onmouseover!passwd! and ! or ! having ! copy !iframe! exec !insert! select !update! count ! chr ! mid ! master ! declare !drop ! drop table !creat! creat table!truncate! char ! like ! exec ! execute ! from ! grant !group_concat!column_name!information_schema.columns!table_schema! union ! where ! order ! count ! sitename ! net user !xp_cmdshell!%20";
        strArray = filterKey.split("\\!");
        String scriptKey = "/xss/!script!onmouseover!expression!onload!prompt!onreadystatechange!$!{!}!<!>!\"!'![!]!%24!%7B!%7D!%28!%29!%3C!%3E!%22!%27!%5B!%5D";
        scriptArray = scriptKey.split("\\!");//
        
        // String specialFile =
        // "index2.jsp!index_right1.jsp!dt_list_right1.jsp!dt_list_right2.jsp!pages/app/index.jsp";
        // specialFileArray = specialFile.split("\\!");//
        String excludeUrlsStr = arg0.getInitParameter("excludeUrls");
        if(StringUtils.isBlank(excludeUrlsStr))
            excludeUrls = new String[0];
        else
            excludeUrls = excludeUrlsStr.split(",");
        
    }
    
    private String parameterFilter(String value)
    {
        if (null == value || "".equals(value))
        {
            return value;
        }
        logger.info("过滤词：" + value);
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < value.length(); i++)
        {
            switch (value.charAt(i))
            {
                case '<' :
                    result.append("&lt;");
                    break;
                case '>' :
                    result.append("&gt;");
                    break;
                case '"' :
                    result.append("&quot;");
                    break;
                case '\'' :
                    result.append("&#39;");
                    break;
                case '(' :
                    result.append("&#40;");
                    break;
                case ')' :
                    result.append("&#41;");
                    break;
                case '+' :
                    result.append("&#43;");
                    break;
                default :
                    result.append(value.charAt(i));
                    break;
            }
        }
        
        return result.toString();
    }
    
    /**
     * true表示合法; false表示非法
     * 
     * @param entry
     * @return
     */
    private boolean filterDbPara(String key, ServletRequest request)
    {
        boolean result = true;// �Ϸ�
        String value = request.getParameter(key);
        // System.out.println("过滤词20120507-filterDbPara-DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD："+value);
        for (int ind = 0; ind < strArray.length; ind++)
        {
            if (value.toUpperCase().indexOf(strArray[ind].toUpperCase()) > -1)
            {
                logger.info("过滤词：" + strArray[ind]);
                result = false;
                break;
            }
        }
        return result;
    }
    
    private boolean filterHtmlPara(String key, ServletRequest request)
    {
        boolean result = true;// 合法
        String value = request.getParameter(key);
        // System.out.println("过滤词20120507-filterHtmlPara-DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD："+value);
        String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; // 定义script的正则表达式
        String regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; // 定义style的正则表达式
        String regEx_html = "[\\s\\S]*?<[^>]+>[\\s\\S]*?"; // 定义HTML标签的正则表达式
        String regEx_html2 = "[\\s\\S]*?<[^>]+/>[\\s\\S]*?"; // 定义HTML标签的正则表达式
        String regEx_html3 = "[\\s\\S]*?<[^>][\\s\\S]*?"; // 定义HTML标签的正则表达式
        Pattern p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
        Matcher m_script = p_script.matcher(value);
        if (m_script.matches())
        { // 过滤script标签
            result = false;
            return result;
        }
        
        Pattern p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
        Matcher m_style = p_style.matcher(value);
        if (m_style.matches())
        { // 过滤style标签
            result = false;
            return result;
        }
        
        Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
        Matcher m_html = p_html.matcher(value);
        if (m_html.matches())
        { // 根据regEx_html过滤html标签
            result = false;
            return result;
        }
        
        Pattern p_html2 = Pattern.compile(regEx_html2, Pattern.CASE_INSENSITIVE);
        Matcher m_html2 = p_html2.matcher(value);
        if (m_html2.matches())
        { // 根据regEx_html2过滤html标签
            result = false;
            return result;
        }
        
        Pattern p_html3 = Pattern.compile(regEx_html3, Pattern.CASE_INSENSITIVE);
        Matcher m_html3 = p_html3.matcher(value);
        if (m_html3.matches())
        { // 根据regEx_html3过滤html标签
            result = false;
            return result;
        }
        if (value.indexOf("||") > -1 || value.indexOf("&&") > -1)
        {
            result = false;
            return result;
        }
        return result;
    }
    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException
    {
        
        // log.info("--CommonParameterFilter--");
        HttpServletRequest hReq = (HttpServletRequest) request;
        HttpServletResponse hRes = (HttpServletResponse) response;
        String hurl = hReq.getRequestURI().toLowerCase();
        if(isExclude(hurl,excludeUrls))
        {
            chain.doFilter(request, response);
            return;
        }
        // 过滤cookies
        Cookie[] cookies = hReq.getCookies();
        if (cookies != null)
        {
            boolean ckResult = true;// 合法
            for (Cookie cookie : cookies)
            {
                if (cookie.getValue() != null && cookie.getValue().indexOf("${") != -1)
                {
                    ckResult = false;
                    break;
                }
                if (cookie.getValue() != null && cookie.getValue().indexOf("#{") != -1)
                {
                    ckResult = false;
                    break;
                }
            }
            if (!ckResult)
            {
                hRes.sendError(hRes.SC_NOT_FOUND, " file not found ");
                return;
            }
        }
        
        // 过滤EL表达式
        Enumeration<?> e = hReq.getHeaderNames();
        if (e != null)
        {
            boolean elResult = true;// 合法
            // 循环遍历
            while (e.hasMoreElements())
            {
                String str = e.nextElement().toString();
                String value = hReq.getHeader(str);
                // 如果有EL表达式
                if (value.indexOf("${") != -1 || value.indexOf("#{") != -1)
                {
                    elResult = false;
                    break;
                }
            }
            
            if (!elResult)
            {
                hRes.sendError(hRes.SC_NOT_FOUND, " file not found ");
                return;
            }
        }
        // 过滤
        // add uniqueid to client cookies
        String isSetUuid = (String) hReq.getSession().getAttribute("isSetUuid");
        if (org.apache.commons.lang.StringUtils.isBlank(isSetUuid) || !"yes".equals(isSetUuid))
        {
            Cookie cookie = new Cookie("uuid_in_cookie", (String) hReq.getSession().getAttribute("uuid_in_session"));
            cookie.setMaxAge(1000 * 60 * 60 * 24 * 365);
            hRes.addCookie(cookie);
            cookie.setPath("/");
            hReq.getSession().setAttribute("isSetUuid", "yes");
        }
        
        boolean result = true;// 合法
        // 处理url中含有脚本关键字---bengin
        // String url = hReq.getRequestURL().toString();
        String url = hReq.getRequestURL().toString() + "?" + hReq.getQueryString();
        
        // **************************************************20120717，直接访问嵌入了iframe的页面，如果不带后面的参数，不让访问（WVS会认为这是个中危漏洞）
        // for (String sp : specialFileArray)
        // {
        // if (url.endsWith(sp + "?null"))
        // {
        // result = false;
        // logger.info("不带适配url，直接访问了页面:" + sp);
        // break;
        // }
        // }
        // if (!result)
        // {
        // hRes.sendError(hRes.SC_NOT_FOUND, " file not found ");
        // return;
        // }
        // ***************************************************20120717
        
        for (String s : scriptArray)
        {
            if (url.trim().toUpperCase().indexOf(s.toUpperCase()) > -1)
            {
                result = false;
                logger.info("关键字：" + s);
                break;
            }
        }
        if (!result)
        {
            hRes.sendError(hRes.SC_NOT_FOUND, " file not found ");
            return;
        }
        // 处理url中含有脚本关键字---end
        hReq.setCharacterEncoding("UTF-8");
        Map mReq = hReq.getParameterMap();
        Iterator iter = mReq.entrySet().iterator();
        while (iter.hasNext())
        {
            Map.Entry entry = (Map.Entry) iter.next();
            if (!filterDbPara(entry.getKey().toString(), hReq) || !filterHtmlPara(entry.getKey().toString(), hReq))
            {
                
                result = false;
                break;
            }
            // 针对post提交的也过滤
            String key = entry.getKey().toString();
            String value = request.getParameter(key);
            for (String s : scriptArray)
            {
                // if(value.trim().toUpperCase().indexOf(s.toUpperCase())>-1){
                if (value.toUpperCase().indexOf(s.toUpperCase()) > -1)
                {
                    result = false;
                    logger.info("关键字：" + s);
                    break;
                }
            }
            
        }
        if (result)
        {
            chain.doFilter(hReq, hRes);
        } else
        {
            hRes.sendError(hRes.SC_NOT_FOUND, " file not found ");
            return;
        }
    }
    
    public static void main(String[] args)
    {
        String value = "http://221.180.20.119:8082/wxcs/details_0.jsp?cid=134158&usessionid=&resourceid=SV140200000220&columnid=&rid=SDT00608098201204191947480076&cid_1=134168&cid_2=134170&nbr_c=5&backurl=http%3A//221.180.20.119%3A8082/wxcs/details_0.jsp%3Fusessionid%3D%26resourceid%3DSV140200000220%26columnid%3D%26rid%3DSDT00619008201204192021400871%26cid%3D134158%26cid_1%3D134168%26cid_2%3D134169%26backurl%3Dhttp%253A//221.180.20.119%253A8082/wxcs/list_1_m.jsp%253Fcid%253D134158%2526nbr_l%253D20%2526nbr_c%253D15%2526nbr_t%253D30%2526nbr_p%253D1%2526areacode%253D140200%2526sticket%253D%2526areacode%253D140200%2526portaltype%253D0%2526columnid%253D%2526version%253D0%2526usessionid%253D%2526resourceid%253DSV140200000220%2526backurl%253Dhttp%25253A%25252F%25252Fdatong.wxcs.cn%25252Fpub%25252Fwebsearchhaskey%25253FsearchKey%25253D%2525C3%2525A5%2525C2%25258A%2525C2%25259E%2525C3%2525A4%2525C2%2525BA%2525C2%25258B%252526searchType%25253D0%26areacode%3D140200%26islogin%3D0&areacode=140200&islogin=0";
        String filterKey = "1 =1!1= 1!1 = 1!%20and%20!%20or%20!%20having%20!onreadystatechange!xss!script! eval !style!expression!iframe! img !onmouseover!passwd! and ! or ! having ! copy !iframe! exec !insert! select !update! count ! chr ! mid ! master ! declare !drop! drop table !creat! creat table!truncate! char ! like ! exec ! execute ! from ! grant !group_concat!column_name!information_schema.columns!table_schema! union ! where ! order ! count ! sitename ! net user !xp_cmdshell!%20!<!>!+!;";
        String[] strArray = filterKey.split("\\!");
        for (int ind = 0; ind < strArray.length; ind++)
        {
            if (value.toUpperCase().indexOf(strArray[ind].toUpperCase()) > -1)
            {
                logger.info("关键q2字：" + strArray[ind]);
                break;
            } else
            {
                logger.info("不存在关键字：");
            }
        }
    }
}
